"""
Python基础学习 - 函数示例代码
=========================

本文件展示了Python中函数的定义和使用：
1. 函数定义和调用 - 将代码组织成可重用的模块
2. 参数传递 - 向函数传递数据的不同方式
3. 作用域 - 变量在程序中的可见范围
4. 闭包 - 函数携带其外部环境的能力
5. 装饰器 - 在不修改原函数的情况下增强函数功能

函数是Python编程的核心概念，它帮助我们将复杂问题分解为更小的、可管理的部分。
"""

# 1. 函数定义和调用
# 函数是一段可重用的代码块，用于执行特定任务
# 使用def关键字定义函数，后面跟函数名和圆括号
# 圆括号中可以包含参数，冒号后是函数体
def basic_function_demo():
    print("=== 函数定义和调用示例 ===")
    
    # 简单函数 - 不带参数的函数
    # 函数可以返回值，使用return关键字
    def greet(name):  # name是函数的参数
        return f"你好, {name}!"  # 返回格式化的问候语
    
    message = greet("张三")  # 调用函数并传入参数
    print(message)
    
    # 带默认参数的函数 - 为参数提供默认值
    # 当调用函数时没有提供该参数的值，就会使用默认值
    def greet_with_title(name, title="先生"):  # title参数有默认值"先生"
        return f"你好, {title} {name}!"
    
    print(greet_with_title("李四"))        # 使用默认title
    print(greet_with_title("王五", "女士"))  # 提供自定义title
    
    # 可变参数函数 - 接受任意数量的位置参数
    # *args表示将所有位置参数收集到一个元组中
    def sum_all(*args):  # args是一个包含所有传入参数的元组
        return sum(args)  # 使用内置sum函数计算总和
    
    print(f"求和结果: {sum_all(1, 2, 3, 4, 5)}")  # 传入5个参数
    
    # 关键字参数函数 - 接受任意数量的关键字参数
    # **kwargs表示将所有关键字参数收集到一个字典中
    def create_profile(name, age, **kwargs):  # kwargs是一个包含所有关键字参数的字典
        profile = {"name": name, "age": age}  # 创建基本信息字典
        profile.update(kwargs)  # 将额外的关键字参数添加到profile中
        return profile
    
    # 调用函数时使用关键字参数传递额外信息
    profile = create_profile("赵六", 25, city="北京", job="工程师")
    print(f"个人资料: {profile}")

# 2. 参数传递示例
# Python中参数传递的方式取决于参数的类型
# 不可变对象（如数字、字符串、元组）传递的是值的副本
# 可变对象（如列表、字典）传递的是对象的引用
def parameter_passing_demo():
    print("\n=== 参数传递示例 ===")
    
    # 不可变对象参数传递 - 传递的是值的副本
    # 在函数内部修改参数不会影响原始变量
    def modify_number(x):  # x是num的副本
        x = x + 10       # 修改的是副本，不影响原始变量
        print(f"函数内部的x: {x}")
    
    num = 5
    print(f"修改前的num: {num}")
    modify_number(num)
    print(f"修改后的num: {num}")  # num没有改变
    
    # 可变对象参数传递 - 传递的是对象的引用
    # 在函数内部修改参数会影响原始变量
    def modify_list(lst):  # lst指向与my_list相同的列表对象
        lst.append(4)      # 修改的是原始列表对象
        print(f"函数内部的lst: {lst}")
    
    my_list = [1, 2, 3]
    print(f"修改前的my_list: {my_list}")
    modify_list(my_list)
    print(f"修改后的my_list: {my_list}")  # my_list被改变了

# 3. 作用域示例
# 作用域决定了变量在程序中的可见范围
# Python中有局部作用域和全局作用域
# 局部变量只在定义它的函数内部可见
# 全局变量在整个程序中都可见
global_var = "我是全局变量"  # 在函数外部定义的变量是全局变量

def scope_demo():
    print("\n=== 作用域示例 ===")
    
    def inner_function():
        # 使用global关键字声明要修改全局变量
        # 没有这个声明，global_var = "我被修改了"会创建一个新的局部变量
        global global_var
        
        local_var = "我是局部变量"  # 在函数内部定义的变量是局部变量
        print(f"在函数内部访问全局变量: {global_var}")  # 可以访问全局变量
        print(f"在函数内部访问局部变量: {local_var}")   # 可以访问局部变量
        
        global_var = "我被修改了"  # 修改全局变量
    
    print(f"在函数外部访问全局变量: {global_var}")
    inner_function()  # 调用内部函数
    print(f"在函数调用后访问全局变量: {global_var}")  # 全局变量已被修改

# 4. 闭包示例
# 闭包是一个函数以及其捕获的外部作用域中的变量
# 闭包可以保存状态，即使外部函数已经执行完毕
def closure_demo():
    print("\n=== 闭包示例 ===")
    
    # 创建乘法器函数 - 演示闭包的基本概念
    # 外部函数返回内部函数，内部函数可以访问外部函数的参数
    def make_multiplier(n):  # 外部函数参数n
        def multiplier(x):   # 内部函数可以访问外部函数的参数n
            return x * n     # 使用外部函数的参数n
        return multiplier     # 返回内部函数
    
    # 创建具体的乘法器
    double = make_multiplier(2)  # 创建一个将数字乘以2的函数
    triple = make_multiplier(3)  # 创建一个将数字乘以3的函数
    
    print(f"10的两倍: {double(10)}")  # 调用闭包函数
    print(f"10的三倍: {triple(10)}")  # 调用闭包函数
    
    # 闭包保存状态 - 演示闭包如何保存和维护状态
    # 每个闭包都有自己的状态，互不影响
    def make_counter():
        count = 0              # 外部函数的局部变量
        def counter():
            nonlocal count     # 声明要修改外部函数的局部变量
            count += 1         # 修改外部函数的局部变量
            return count       # 返回当前计数值
        return counter          # 返回内部函数
    
    # 创建独立的计数器
    counter1 = make_counter()  # counter1有自己的count变量
    counter2 = make_counter()  # counter2有自己的count变量
    
    # 每个计数器维护自己的状态
    print(f"计数器1: {counter1()}, {counter1()}, {counter1()}")  # 1, 2, 3
    print(f"计数器2: {counter2()}, {counter2()}")                 # 1, 2

# 5. 装饰器示例
# 装饰器是一种特殊类型的函数，它可以修改其他函数的行为
# 装饰器在不修改原函数代码的情况下，为函数添加新功能
def decorator_demo():
    print("\n=== 装饰器示例 ===")
    
    # 简单装饰器 - 为函数添加额外功能
    # 装饰器函数接受一个函数作为参数，并返回一个新的函数
    def my_decorator(func):      # func是要被装饰的函数
        def wrapper(*args, **kwargs):  # wrapper可以接受任意参数
            print("函数调用前执行")      # 在原函数执行前的操作
            result = func(*args, **kwargs)  # 调用原函数
            print("函数调用后执行")      # 在原函数执行后的操作
            return result           # 返回原函数的结果
        return wrapper            # 返回包装后的函数
    
    # 使用@语法糖应用装饰器
    # @my_decorator等价于say_hello = my_decorator(say_hello)
    @my_decorator
    def say_hello(name):
        print(f"你好, {name}!")
        return f"问候{name}完成"
    
    result = say_hello("张三")  # 调用被装饰的函数
    print(f"装饰器函数返回值: {result}")
    
    # 带参数的装饰器 - 创建可配置的装饰器
    # 外层函数接受装饰器参数，中层函数接受被装饰的函数，内层函数执行实际装饰
    def repeat(times):           # 装饰器参数
        def decorator(func):     # 被装饰的函数
            def wrapper(*args, **kwargs):  # 实际执行的函数
                for _ in range(times):     # 重复执行指定次数
                    result = func(*args, **kwargs)
                return result
            return wrapper        # 返回包装函数
        return decorator          # 返回装饰器函数
    
    # 应用带参数的装饰器
    # @repeat(3)等价于greet = repeat(3)(greet)
    @repeat(3)
    def greet(name):
        print(f"欢迎, {name}!")
    
    greet("李四")  # 调用被装饰的函数

# 主函数 - 程序的入口点
# 当直接运行这个Python文件时，会执行main()函数
def main():
    # 按顺序执行各个演示函数
    basic_function_demo()
    parameter_passing_demo()
    scope_demo()
    closure_demo()
    decorator_demo()

# 这是一个Python的特殊机制
# 当直接运行这个文件时（而不是导入它），
# __name__变量的值会是"__main__"，从而执行main()函数
if __name__ == "__main__":
    main()